package com.aabte.spring.annotation;

import com.aabte.spring.annotation.config.ComponentScanConfig;
import com.aabte.spring.beans.Person;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.*;
import org.springframework.beans.factory.support.*;
import org.springframework.context.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.support.*;
import org.springframework.context.weaving.LoadTimeWeaverAwareProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;

import java.util.Arrays;

/**
 * Spring容器的refresh流程：{@link AbstractApplicationContext#refresh()} ()}
 *  1、刷新预处理 {@link AbstractApplicationContext#prepareRefresh()}
 *      1、初始化一些属性设置，子类自定义个性化的属性设置方法 {@link AbstractApplicationContext#initPropertySources}
 *      2、属性校验 {@link ConfigurableEnvironment#validateRequiredProperties}
 *      3、保存容器中的一些早期事件{@link ApplicationEvent}
 *  2、获取BeanFactory，{@link AbstractApplicationContext#obtainFreshBeanFactory}
 *      1、刷新BeanFactory {@link AbstractApplicationContext#refreshBeanFactory}
 *          1、在构造器{@link GenericApplicationContext}中创建一个{@link DefaultListableBeanFactory}对象
 *          2、设置{@link BeanFactory}序列化ID
 *      2、获取{@link GenericApplicationContext#getBeanFactory}，并返回{@link ConfigurableListableBeanFactory}
 *  3、BeanFactory预准备工作 {@link AbstractApplicationContext#prepareBeanFactory(ConfigurableListableBeanFactory)}
 *      1、设置BeanFactory的类加载器、表达式解析器等等
 *      2、添加部分BeanPostProcessor组件{@link org.springframework.context.support.ApplicationContextAwareProcessor}
 *      3、设置需要忽略的自动装配的接口：{@link EnvironmentAware}、{@link EmbeddedValueResolverAware}等等
 *      4、设置默认就可以注入的自动装配的接口：{@link BeanFactory}、{@link ApplicationContext}、{@link ResourceLoader}、{@link ApplicationEventPublisher}
 *      5、添加{@link org.springframework.context.support.ApplicationListenerDetector}组件
 *      6、添加编译时的AspectJ组件 {@link LoadTimeWeaverAwareProcessor} {@link ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME}
 *      7、注册环境对象 {@link ConfigurableEnvironment}
 *      8、注册系统属性
 *      9、注册系统环境信息
 *  4、BeanFactory预准备工作完成后，调用子类的预准备工作，默认空 {@link AbstractApplicationContext#postProcessBeanFactory}
 *  5、执行容器中保存的BeanFactory后置处理器 {@link AbstractApplicationContext#invokeBeanFactoryPostProcessors}
 *     后置处理器有两个接口：{@link BeanFactoryPostProcessor}、{@link BeanDefinitionRegistryPostProcessor}
 *      1、从容器中获取所有的{@link BeanFactoryPostProcessor}
 *      1、获取所有{@link BeanDefinitionRegistryPostProcessor}
 *      2、先执行实现了{@link PriorityOrdered}接口的处理器
 *      3、然后执行实现了{@link Ordered}接口的处理器
 *      4、最后执行剩下没有实现任务优先级或顺序接口的处理器
 *      5、执行{@link BeanFactoryPostProcessor#postProcessBeanFactory(ConfigurableListableBeanFactory)}
 *      6、执行{@link BeanDefinitionRegistryPostProcessor#postProcessBeanFactory(ConfigurableListableBeanFactory)}
 *  6、注册Bean后置处理器，用于拦截Bean的创建过程 {@link AbstractApplicationContext#registerBeanPostProcessors}
 *     {@link BeanPostProcessor}接口下有如下几个子接口，每种后置处理器执行时机不同，但都有优先级处理：
 *     {@link DestructionAwareBeanPostProcessor}
 *     {@link InstantiationAwareBeanPostProcessor}  Bean实例化之前回调
 *     {@link SmartInstantiationAwareBeanPostProcessor}
 *     {@link MergedBeanDefinitionPostProcessor}   Bean实例化之后回调
 *      1、获取所有{@link BeanPostProcessor}
 *      2、首先注册实现了{@link PriorityOrdered}接口的处理器
 *      3、再注册实现了{@link Ordered}接口的处理器
 *      4、注册没有实现优先级相关接口的处理器
 *      5、最后注册{@link MergedBeanDefinitionPostProcessor}处理器
 *      6、注册一个{@link org.springframework.context.support.ApplicationListenerDetector}处理器，在Bean创建完成后检查是否是{@link ApplicationListener}，如果是添加到监听器列表
 *  7、初始化{@link MessageSource}组件，用于MVC国际化、消息绑定 {@link AbstractApplicationContext#initMessageSource}
 *      1、获取{@link ConfigurableListableBeanFactory}对象
 *      2、判断容器中是否有{@link AbstractApplicationContext#MESSAGE_SOURCE_BEAN_NAME}组件
 *      3、如果有，直接使用
 *      4、如果没有
 *          1、创建一个{@link DelegatingMessageSource}
 *          2、把创建的{@link MessageSource}组件注册在容器中
 *  8、初始化事件多播器{@link ApplicationEventMulticaster} {@link AbstractApplicationContext#initApplicationEventMulticaster}
 *      1、获取{@link ConfigurableListableBeanFactory}对象
 *      2、判断容器中是否有{@link AbstractApplicationContext#APPLICATION_EVENT_MULTICASTER_BEAN_NAME}组件
 *      3、如果有，直接使用
 *      4、如果没有
 *          1、创建一个{@link SimpleApplicationEventMulticaster}
 *          2、把创建的{@link ApplicationEventMulticaster}组件注册在容器中
 *  9、调用子类实现 {@link AbstractApplicationContext#onRefresh}，留给子类重写此方法，在容器刷新时执行自定义代码
 *  10、注册监听器{@link ApplicationListener} {@link AbstractApplicationContext#registerListeners}
 *      1、从容器中获取所有{@link ApplicationListener}组件
 *      2、将所有监听器组件添加到事件多播器中
 *      3、派发之前步骤产生的事件
 *  11、实例化剩下所有Bean {@link AbstractApplicationContext#finishBeanFactoryInitialization}
 *      1、获取所有未实例化的Bean名称
 *      2、遍历所有Bean，依次进行实例化和初始化操作 {@link DefaultListableBeanFactory#preInstantiateSingletons}
 *          1、获取Bean的定义信息{@link RootBeanDefinition}
 *          2、判断不是抽象、是单例、不是懒加载
 *              1、判断是否是工厂Bean，如果是调用{@link FactoryBean#getObject()}
 *              2、不是工厂Bean，调用{@link AbstractBeanFactory#getBean(String)} {@link AbstractBeanFactory#doGetBean}
 *                  1、从已创建好的单例Beans中找是否已经创建 {@link AbstractBeanFactory#getSingleton(String)}
 *                  2、没有找到，开始创建Bean
 *                  3、标记当前Bean已经创建
 *                  4、获取当前Bean的定义信息
 *                  5、获取当前Bean依赖的其它Bean，如果有调用{@link AbstractBeanFactory#getBean(String)}先创建依赖的Bean
 *                  6、创建当前Bean {@link AbstractAutowireCapableBeanFactory#doCreateBean(String, RootBeanDefinition, Object[])} )}
 *                      1、获取Bean的定义信息{@link RootBeanDefinition}
 *                      2、创建Bean之前，回调{@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}处理器 {@link AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation}
 *                      3、如果有返回值，执回调{@link InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation}
 *                      4、如果没有返回值，执行{@link AbstractAutowireCapableBeanFactory#doCreateBean}，利用工厂方法和构造器创建Bean
 *                          1、调用{@link AbstractAutowireCapableBeanFactory#createBeanInstance}方法，利用工厂方法和构造器创建Bean
 *                          2、回调{@link AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors}方法
 *                      5、给Bean属性赋值 {@link AbstractAutowireCapableBeanFactory#populateBean}
 *                          1、属性赋值之前，回调{@link InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation(Object, String)}
 *                          2、属性赋值之前，回调{@link InstantiationAwareBeanPostProcessor#postProcessPropertyValues}
 *                          3、给属性赋值 {@link AbstractAutowireCapableBeanFactory#applyPropertyValues}
 *                      6、执行Bean的初始化方法 {@link AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)}
 *                          1、回调{@link org.springframework.beans.factory.Aware}相关接口：{@link BeanNameAware}、{@link BeanClassLoaderAware}、{@link BeanFactoryAware}
 *                          2、初始化之前执行后置处理器 {@link AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization}
 *                          3、执行初始化方法 {@link AbstractAutowireCapableBeanFactory#invokeInitMethods}
 *                              1、如果是{@link InitializingBean}类型，执行{@link InitializingBean#afterPropertiesSet()}
 *                              2、如果{@link RootBeanDefinition}中有自定义的初始化方法，执行自定义初始化方法{@link AbstractAutowireCapableBeanFactory#invokeCustomInitMethod}
 *                          4、初始化之后执行后置处理器 {@link AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization(Object, String)}
 *                      7、注册Bean的销毁方法 {@link AbstractAutowireCapableBeanFactory#registerDisposableBeanIfNecessary}
 *                  7、将创建的Bean保存到缓存中singletonObjects  {@link DefaultSingletonBeanRegistry#addSingleton}
 *      3、所有Bean都创建完成后，查检所有Bean如果是{@link SmartInitializingSingleton}类型，则回调{@link SmartInitializingSingleton#afterSingletonsInstantiated()}
 *  12、完成容器刷新操作 {@link AbstractApplicationContext#finishRefresh} {@link DefaultListableBeanFactory#preInstantiateSingletons}
 *      1、初始化生命周期有关的后置处理器 {@link AbstractApplicationContext#initLifecycleProcessor}，自定义实现{@link LifecycleProcessor}接口
 *         首先从容器中获取，如果没有创建一个{@link DefaultLifecycleProcessor}
 *      2、从容器中获取{@link LifecycleProcessor}处理器，并回调{@link LifecycleProcessor#onRefresh()}
 *      3、发布{@link ContextRefreshedEvent}事件
 *      4、最后注册容器{@link LiveBeansView#registerApplicationContext}
 *
 * 小结：
 * 1、Spring容器启动时，先会保存所有注册进来的Bean的定义信息
 *      1、XML注册Bean
 *      2、注解注册Bean：{@link org.springframework.stereotype.Service}、{@link org.springframework.stereotype.Component}、{@link org.springframework.stereotype.Repository}
 * 2、Spring容器会在合适的时候创建这些Bean
 *      1、用到这个Bean的时候，调用getBean方法来创建Bean，创建好后保存到容器中
 *      2、最后统一创建剩下所有的单例bean
 * 3、后置处理器
 *      1、每一个Bean创建时，都会使用各种后置处理器进行拦截，来增强bean功能
 *          {@link AutowiredAnnotationBeanPostProcessor}  自动注入注解处理器
 *          {@link AnnotationAwareAspectJAutoProxyCreator}  AOP注解处理器
 *          {@link AsyncAnnotationBeanPostProcessor} 异步任务注解处理器
 * 4、事件驱动模型：
 *      {@link ApplicationListener} 事件监听器
 *      {@link ApplicationEventMulticaster} 事件多播器（派发器）
 *
 * @author Daniel
 */
public class MainTest {

    public static void main(String[] args) {

        ApplicationContext ioc = new AnnotationConfigApplicationContext(ComponentScanConfig.class);

        Person jack = (Person)ioc.getBean("jack");

        System.out.println("jack = " + jack);

        String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
        System.out.println("beanDefinitionNames = " + Arrays.asList(beanDefinitionNames));



    }

}
